#ifdef _WINDOWS
#include <windows.h>
#endif

#include <gl/gl.h>
#include <gl/glu.h>
#include <math.h>
#include <stdio.h>

#include "CGfxOpenGL.h"
#include "gmath.h"

// disable float-double conversion warnings
#pragma warning(disable:4305)
#pragma warning(disable:4244)

extern bool Wireframe;

CGfxOpenGL::CGfxOpenGL()
{
}

CGfxOpenGL::~CGfxOpenGL()
{
    Shutdown();
}

bool CGfxOpenGL::Init()
{	
    // erase the background to black
	glClearColor(0.0, 0.0, 0.0, 0.0);

    // initialize a rotation angle
    m_angle = 0.0f;

    // create a quadric object for drawing spheres
    m_Quadric = gluNewQuadric();

    return true;
}

bool CGfxOpenGL::Shutdown()
{
    // delete the quadric object
    if (m_Quadric != NULL) {
        gluDeleteQuadric(m_Quadric);
        m_Quadric = NULL;
    }
	return true;
}

void CGfxOpenGL::SetupProjection(int width, int height)
{
	if (height == 0)					// don't want a divide by zero
	{
		height = 1;					
	}

	glViewport(0, 0, width, height);		// reset the viewport to new dimensions
	glMatrixMode(GL_PROJECTION);			// set projection matrix current matrix
	glLoadIdentity();						// reset projection matrix

	// calculate aspect ratio of window
	gluPerspective(52.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);

	glMatrixMode(GL_MODELVIEW);				// set modelview matrix
	glLoadIdentity();						// reset modelview matrix

	m_windowWidth = width;
	m_windowHeight = height;
}

void CGfxOpenGL::Prepare(float dt)
{
    // update the rotation angle
    m_angle += dt;
}

// draw a normal form the center of poly defined by p1, p2, p3
// using the normal value
// this function used to test/visualize the normal value
void DrawNormal(Vector3& p1, Vector3& p2, Vector3& p3, Vector3& normal) {
    Vector3 center;

    // compute the center of the poly
    center = p1 + p2 + p3;
    center.scale(1.0/3.0);

    // temporarily disable lighting to draw the normal line
    glDisable(GL_LIGHTING);

    // draw a small white line to represent the normal
    glBegin(GL_LINES);
        glColor3f(1.0, 1.0, 1.0);
        glVertex3f(center.x, center.y, center.z);
        glColor3f(1.0, 1.0, 1.0);
        glVertex3f(center.x + normal.x, center.y + normal.y, center.z + normal.z);
    glEnd();

    // re-enable lighting
    glEnable(GL_LIGHTING);
}


// define a single sided face
struct Face {
    int i1, i2, i3;             // indexes into vertex data
};

void CGfxOpenGL::Render()
{	
    int numFaces = 8;

    Vector3 p1, p2, p3;			// points or vertices of the triangle
	Vector3 V1, V2;				// the vectors which make up a poly
	Vector3 normal;				// the normal for each face

    // define 6 vertices of a diamond shape - colors not being used now
    Vector3 vertexes[] = {
        Vector3(0, 2, 0),		// vertex 0
        Vector3(1, 0, 1),		// vertex 1
        Vector3(1, 0, -1),		// vertex 2 
        Vector3(-1, 0, -1),		// vertex 3 
        Vector3(-1, 0, 1),		// vertex 4
        Vector3(0, -2, 0)		// vertex 5
    };

    // set up the face index data into the vertex array above
    // each triple will define a single face (triangle) of our shape
    Face faceData[] =
	{
        0, 4, 1,				// top front-facing face
        0, 3, 4,				// top left face
        0, 2, 3,				// top rear face
        0, 1, 2,				// top right face
        5, 1, 4,				// bottom front face ...
        5, 4, 3,
        5, 3, 2, 
        5, 2, 1,
    };

    // clear screen and depth buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     
    glLoadIdentity();

	// enable z or depth buffer testing
    glEnable(GL_DEPTH_TEST);
	glEnable(GL_NORMALIZE);

    if (Wireframe)
	{
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    }
    else
	{
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }

	float light0_Position[] = {0, 0, 0, 1};
	float ambient_light[] = {0.5, 0.5, 0.5, 1.0};
	float diffuse_light[] = {0.5, 0.5, 0.5, 1.0};
	float specular_light[] = {0.5, 0.5, 0.5, 1.0};
	float ambient_color[] = {0.5, 0.2, .6, 1.0};
	float diffuse_color[] = {1.0, 0.0, 0.0, 1.0};		// color of sphere
	float specular_color[] = {0.9, 0.0, 0.9, 1.0};

	// temporarily disable lighting
	glDisable(GL_LIGHTING);

	// move the whole scene back 
    glTranslatef(0.0, 0.0, -10.0f);

    // set up a temporary transform for the orbiting sphere
    glPushMatrix();
	//
        // make light rotate about an odd axis
        glRotatef(m_angle, 1.0f, 1.0f, 0.0f);

        // move the light into upper left corner of the scene
        glTranslatef(-2.0, 2.0, 3.0f);

        // draw a small sphere for light position
		glEnable(GL_LIGHT0);
		glLightfv(GL_LIGHT0, GL_POSITION, light0_Position);
		glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_light);		
		glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_light);		
		glLightfv(GL_LIGHT0, GL_SPECULAR, specular_light);

		glColor3fv(diffuse_color);		// draw sphere with this color
        gluSphere(m_Quadric, 0.2, 10, 10);
	//
    glPopMatrix();

	// enable lighting to be used
	glEnable(GL_LIGHTING);

    // rotate object about Y
    glRotatef(m_angle*2, 0.0f, 1.0f, 0.0f);
	
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient_color);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse_color);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular_color);
	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 128);

	// for each of the 8 faces
    for (int i=0; i < numFaces; i++)
	{
		p1 = vertexes[faceData[i].i1];
        p2 = vertexes[faceData[i].i2];
		p3 = vertexes[faceData[i].i3];

		V1 = p2 - p1;
		V2 = p3 - p1;

		normal = CrossProduct(V1, V2);
		
		normal.normalize();

		// draw the faces that make up the diamond shape
        glBegin(GL_TRIANGLES);

            // draw 3 vertices with color, light and normal info
            // vertex 1
			glNormal3f(normal.x, normal.y, normal.z);
            glVertex3f(p1.x, p1.y, p1.z);

            // vertex 2
			glNormal3f(normal.x, normal.y, normal.z);
            glVertex3f(p2.x, p2.y, p2.z);

            // vertex 3
			glNormal3f(normal.x, normal.y, normal.z);
            glVertex3f(p3.x, p3.y, p3.z);
    
        glEnd();
    }
}

